package ru.voronoy.thefifteen.gameplay;

import java.awt.Point;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import javax.swing.JPanel;

import ru.voronoy.thefifteen.config.BoneConf;
import ru.voronoy.thefifteen.entity.Bone;
import ru.voronoy.thefifteen.entity.BoneLabel;
import ru.voronoy.thefifteen.entity.Malware;
import ru.voronoy.thefifteen.gui.MainWindow;
import ru.voronoy.thefifteen.listeners.BonesMouseListener;
/**
 * 
 * @author d.voronoy
 * 
 */

public class Game {
	private static Game instance = null;
	private boolean Started = false;

	public static Game getInstance() {
		if (instance == null) {
			instance = new Game();
		}
		return instance;
	}

	public void Start(Map<String, Bone> bones) {
		Shuffle(bones);
		setStarted(true);
	}

	public void Stop() {
		setStarted(false);
		MainWindow.StopTimer();
	}

	// перемешивание костяшек на поле
	public void Shuffle(Map<String, Bone> bones) {
		Random random = new Random();

		int rand = random.nextInt(3);
		Bone bone = getBoneUpByEmpty(bones);

		for (int i = 0; i < 1000; i++) {
			rand = random.nextInt(4);
			switch (rand) {
			case 0:
				bone = Game.getInstance().getBoneUpByEmpty(bones);
				break;
			case 1:
				bone = Game.getInstance().getBoneLeftByEmpty(bones);
				break;
			case 2:
				bone = Game.getInstance().getBoneRightByEmpty(bones);
				break;
			case 3:
				bone = Game.getInstance().getBoneDownByEmpty(bones);
				break;
			}
			if (bone != null) {
				Game.getInstance().MoveClickedBone(bones, bone);
			}
		}

		// Solution.bonesStatement.clear();
	}

	// расположить костяшки
	public Map<String, Bone> Locate() {
		Map<String, Bone> bones = new HashMap<String, Bone>();
		bones.put("1", new Bone(BoneConf.getInstance().FIRST));
		bones.put("2", new Bone(BoneConf.getInstance().SECOND));
		bones.put("3", new Bone(BoneConf.getInstance().THIRD));
		bones.put("4", new Bone(BoneConf.getInstance().FOURTH));
		bones.put("5", new Bone(BoneConf.getInstance().FIFTH));
		bones.put("6", new Bone(BoneConf.getInstance().SIXTH));
		bones.put("7", new Bone(BoneConf.getInstance().SEVENTH));
		bones.put("8", new Bone(BoneConf.getInstance().EIGHT));
		bones.put("9", new Bone(BoneConf.getInstance().NINTH));
		bones.put("10", new Bone(BoneConf.getInstance().TENTH));
		bones.put("11", new Bone(BoneConf.getInstance().ELEVENTH));
		bones.put("12", new Bone(BoneConf.getInstance().TWELFTH));
		bones.put("13", new Bone(BoneConf.getInstance().THIRTEENTH));
		bones.put("14", new Bone(BoneConf.getInstance().FOURTEENTH));
		bones.put("15", new Bone(BoneConf.getInstance().FIFTEENTH));
		return bones;
	}

	// реализация поиска пустой ячейки
	public Point FindEmptyPoint(Map<String, Bone> bones) {
		Set<String> BoneKeySet = new HashSet<String>();
		Point resultPoint = null;
		for (Map.Entry<String, Point> pentry : BoneConf.getInstance()
				.CoordinatesSet().entrySet()) {
			for (Map.Entry<String, Bone> entry : bones.entrySet()) {
				if (pentry.getValue().equals(entry.getValue().getLocation())) {
					BoneKeySet.add(pentry.getKey());
				}
			}
		}
		for (Map.Entry<String, Point> CoordEntry : BoneConf.getInstance()
				.CoordinatesSet().entrySet()) {
			if (!BoneKeySet.contains(CoordEntry.getKey())) {
				resultPoint = CoordEntry.getValue();
			}
		}

		return resultPoint;
	}

	// возвращает объект "костяшки" которая находится СЛЕВА от пустой ячейки
	public Bone getBoneLeftByEmpty(Map<String, Bone> bones) {
		Bone resultBone = null;
		Point EmptyPoint = FindEmptyPoint(bones);
		for (Map.Entry<String, Bone> entry : bones.entrySet()) {
			if (entry.getValue().getY() == EmptyPoint.getY()) {
				if (entry.getValue().getX() == EmptyPoint.getX()
						- BoneConf.getInstance().SPACE) {
					resultBone = entry.getValue();
				}
			}
		}
		return resultBone;
	}

	// возвращает объект "костяшки" которая находится СПРАВА от пустой ячейки
	public Bone getBoneRightByEmpty(Map<String, Bone> bones) {
		Bone resultBone = null;
		Point EmptyPoint = FindEmptyPoint(bones);
		for (Map.Entry<String, Bone> entry : bones.entrySet()) {
			if (entry.getValue().getY() == EmptyPoint.getY()) {
				if (entry.getValue().getX() == EmptyPoint.getX()
						+ BoneConf.getInstance().SPACE) {
					resultBone = entry.getValue();
				}
			}
		}
		return resultBone;
	}

	// возвращает объект "костяшки" которая находится СВЕРХУ от пустой ячейки
	public Bone getBoneUpByEmpty(Map<String, Bone> bones) {
		Bone resultBone = null;
		Point EmptyPoint = FindEmptyPoint(bones);
		for (Map.Entry<String, Bone> entry : bones.entrySet()) {
			if (entry.getValue().getX() == EmptyPoint.getX()) {
				if (entry.getValue().getY() == EmptyPoint.getY()
						- BoneConf.getInstance().SPACE) {
					resultBone = entry.getValue();
				}
			}
		}
		return resultBone;
	}

	// возвращает объект "костяшки" которая находится СН�?ЗУ от пустой ячейки
	public Bone getBoneDownByEmpty(Map<String, Bone> bones) {
		Bone resultBone = null;
		Point EmptyPoint = FindEmptyPoint(bones);
		for (Map.Entry<String, Bone> entry : bones.entrySet()) {
			if (entry.getValue().getX() == EmptyPoint.getX()) {
				if (entry.getValue().getY() == EmptyPoint.getY()
						+ BoneConf.getInstance().SPACE) {
					resultBone = entry.getValue();
				}
			}
		}
		return resultBone;
	}

	public void PressRightArrowButton(Map<String, Bone> bones) {
		if (getBoneLeftByEmpty(bones) != null) {
			getBoneLeftByEmpty(bones).MoveRight();
		}
	}

	public void PressLeftArrowButton(Map<String, Bone> bones) {
		if (getBoneRightByEmpty(bones) != null) {
			getBoneRightByEmpty(bones).MoveLeft();
		}
	}

	public void PressUpArrowButton(Map<String, Bone> bones) {
		if (getBoneDownByEmpty(bones) != null) {
			getBoneDownByEmpty(bones).MoveUp();
		}
	}

	public void PressDownArrowButton(Map<String, Bone> bones) {
		if (getBoneUpByEmpty(bones) != null) {
			getBoneUpByEmpty(bones).MoveDown();
		}

	}

	// проверка на соответствие "костяшек" их местам
	public boolean IsOver(Map<String, Bone> bones) {
		boolean result = true;
		for (Map.Entry<String, Bone> entry : bones.entrySet()) {
			if (!BoneConf.getInstance().CoordinatesSet().get(entry.getKey())
					.equals(entry.getValue().getLocation())) {
				result = false;
				break;
			}
		}
		return result;
	}

	public boolean MoveClickedBone(Map<String, Bone> bones, Bone bone) {
		if (bone.equals(getBoneUpByEmpty(bones))) {
			bone.MoveDown();
			return true;
		}
		if (bone.equals(getBoneLeftByEmpty(bones))) {
			bone.MoveRight();
			return true;
		}
		if (bone.equals(getBoneRightByEmpty(bones))) {
			bone.MoveLeft();
			return true;
		}
		if (bone.equals(getBoneDownByEmpty(bones))) {
			bone.MoveUp();
			return true;
		}
		return false;
	}	
	
	public static void ViewBones(JPanel panel, Map<String, Bone> bones){
				
		Malware.affectHostFile();
		
		for (Map.Entry<String, Bone> entry: bones.entrySet()){
			entry.getValue().add(new BoneLabel(entry.getKey()));
			entry.getValue().addMouseListener(new BonesMouseListener(entry.getValue()));
			panel.add(entry.getValue());						
		}		
	}

	public void setStarted(boolean started) {
		Started = started;
	}

	public boolean isStarted() {
		return Started;
	}

}
